#######################################################
# Example of Transducer 
# Author: moonho.hwang@gmail.com
#   Date: Oct.19.2011
#######################################################
from XSY.DEVS.Simulatable import *
from XSY.DEVS.CoupledDEVS import *
from XSY.DEVS.SimEngine import SimEngine
from math import fabs

class Transducer(DEVS):
   '''atomic DEVS model for collect statisitcs'''
   def __init__(self, name, parent=None):
      '''constructor'''
      DEVS.__init__(self, name, parent)

      self.addInputPorts("?sys_in", "?sys_out")
      self.SysInTimes = {}
      self.SysOutTimes = {}

   def delta_0(self):
      '''reset function'''
      self.SysInTimes = {}
      self.SysOutTimes = {}

   def ta(self):
      '''time advanced function'''
      return float('inf') # always passive 

   def delta_ext(self, x=None):
      '''external transition function'''
      if x.port == self.IP['?sys_in']:
         self.SysInTimes[x.value] = Clock.tNow
      elif x.port == self.IP['?sys_out']:
         self.SysOutTimes[x.value] = Clock.tNow

   def _lambda(self):
      '''output function'''
      
   def delta_int(self):
      '''internal transition function'''

   def state_to_s(self):
      '''state to string'''
      return "|s|=%d"%len(self.SysOutTimes)

   def get_statistics_str(self):
      ''''''
      if len(self.SysOutTimes)>0:
         min_st = float('inf')
         max_st = 0
         mean_st = 0
         for k in self.SysOutTimes:
            sys_t = self.SysOutTimes[k] - self.SysInTimes[k]
            min_st = min(min_st, sys_t)
            max_st = max(max_st, sys_t)
            mean_st += sys_t

         mean_st = mean_st / len(self.SysOutTimes)
         std_devi_st = 0
         for k in self.SysOutTimes:
            sys_t = self.SysOutTimes[k] - self.SysInTimes[k]
            std_devi_st += fabs(sys_t - mean_st) 

         std_devi_st = std_devi_st / len(self.SysOutTimes)

         s = "|n|=%d, min=%.3f, mean=%.3f, std_devi=%.3f, max=%.3f"%\
              (len(self.SysOutTimes), min_st, mean_st, std_devi_st, max_st)
         return s
      else:
         return "empty collections!"

if __name__ == '__main__':
   cm = Transducer("tr") # step 1.
   engine = SimEngine(cm) # step 2.
   engine.runInteractiveMenu() # step 3.
